import asyncio
import datetime
from random import randint
from typing import Iterable, Callable

from aiogram import Router, F, exceptions, types
from aiogram.fsm.context import FSMContext
from aiogram.filters import IS_ADMIN, ChatMemberUpdatedFilter, JOIN_TRANSITION, LEAVE_TRANSITION, IS_NOT_MEMBER, \
    IS_MEMBER
from aiogram.types import Message, CallbackQuery
from aiogram.utils.markdown import hunderline, hlink, hbold
from apscheduler.job import Job
from apscheduler.triggers.date import DateTrigger

from keyboards import menu_keys
from keyboards.callbacks_data import MenuCategory
from loader import scheduler, bot, logger
from async_db import Database

db = Database()

router = Router()
router.message.filter(~F.chat.type.in_({'private', 'channel'}))
router.message.filter(F.from_user)


async def delete_mess(m: Message):
    try:
        await bot.delete_message(m.chat.id, m.message_id)
    except Exception as e:
        if "message to delete not found" in e.message:
            logger.error(f'{e.message}\t\t{m}')

async def answer_mess(m: Message, text: str, reply_markup=None, delete_timer: int = 0):
    to_del = await m.answer(text, reply_markup=reply_markup)
    if delete_timer != 0:
        await scheduled_function(delete_mess, (to_del,), delete_timer)


async def check_subs(require_channels_id: Iterable[int], user_id):
    subs = []
    for chat in require_channels_id:
        # try:
        sub = await bot.get_chat_member(chat, user_id)
        # except exceptions.TelegramBadRequest:
        #     continue
        if sub.status == 'left':
            return False
        if sub.status in ['member', "creator"]:
            subs.append(sub)
    if len(subs) == len(require_channels_id):
        return True
    # else:
    #     return False


async def check_bot_admin(m: Message):
    adm = None
    admins = [i.user.id for i in await bot.get_chat_administrators(m.chat.id)]
    me = await bot.get_me()
    if me.id in admins:
        adm = me
    return adm


@router.message(
    F.new_chat_participant,
    F.left_chat_member,
)
# @router.message(
# ChatMemberUpdatedFilter(member_status_changed=JOIN_TRANSITION),
# ChatMemberUpdatedFilter(member_status_changed=LEAVE_TRANSITION),
# ChatMemberUpdatedFilter(member_status_changed=IS_NOT_MEMBER >> IS_MEMBER),
# )
async def join_user(m: Message):
    if hasattr(m, 'new_chat_member') or hasattr(m, 'left_chat_participant'):
        try:
            await m.delete()
            logger.success(f"{m.chat.title}: {m}")
            return True
        except exceptions.TelegramBadRequest as e:
            logger.error(f"{m.chat.title}({m.chat.id}): {e.message}")
            return True
    else:
        return False


async def scheduled_function(func, args: tuple = (), start_time: int = randint(2, 10)):
    time = datetime.datetime.now() + datetime.timedelta(seconds=start_time)
    task = scheduler.add_job(func, args=args, trigger='date', next_run_time=time)
    logger.debug(f"{task} / {args}")
    return task.func


async def any_mess(m: Message):
    await scheduled_function(answer_mess, (m, m.text, None, 3), 2)
    await scheduled_function(delete_mess, (m,), 5)


@router.message()
async def any_mess2(m: Message, context: dict):
    if await join_user(m):
        return
    logger.debug(m)
    # TODO Drop to modules: require_channels, default_words, stop_words

    admins = [i.user.id for i in await bot.get_chat_administrators(m.chat.id)]
    if m.from_user.id in admins:
        logger.info('admin')
        return

    words_in_chat = []
    users = context["users"]
    user = None
    require_channel_id = []

    no_admin_text = f'В чате {hbold(m.chat.title)} бот не может нормально работать ' \
                    f'из-за того что не назначен там администратором или не имеет прав удалять сообщения'

    for c in users:
        if m.chat.id in c.chats_id:
            user = c
            break

    if user:
        words_in_chat = user.stop_words
        if m.chat.id in user.require_channel_id.keys():
            require_channel_id = user.require_channel_id[m.chat.id]

    if require_channel_id:
        if hasattr(m, 'new_chat_member'):
            text = f'Привет, {hlink(m.from_user.full_name, f"tg://user?id={m.from_user.id}")}\n' \
                   f'Чтобы начать общение в этом чате подпишись по ссылкам ниже и нажми кнопку чтобы проверить подписку\n'
            await scheduled_function(answer_mess,
                                     (m, text, await menu_keys.list_subs_keys(require_channel_id, m.from_user.id), 240))

        no_subscribe_text = f'{hlink(m.from_user.full_name, f"tg://user?id={m.from_user.id}")},\n' \
                            f'❗️ Вы не подписались на каналы, поэтому Ваше сообщение удаляется.\n' \
                            f'✅ Подпишитесь на каналы, указанные ниже и сможете писать в чат.\n'
        subscribe = await check_subs(require_channel_id, m.from_user.id)
        if not subscribe:
            # await db.jobs_add(2, m.chat.id, no_subscribe_text)
            await scheduled_function(answer_mess, (
                m, no_subscribe_text, await menu_keys.list_subs_keys(require_channel_id, m.from_user.id), 30))
            try:
                await m.delete()
                logger.success(f'[req_channel] {m.chat.title} | {m.from_user.full_name}: Писал не подписавшись')
            except exceptions.TelegramBadRequest as e:
                adm = await check_bot_admin(m)
                if not adm:
                    await bot.send_message(user.client_id, no_admin_text)
                    logger.error(f'[req_channel] {e} | {m.chat.title}({m.chat.id}): {m.from_user.full_name}')
            return
    # TODO add support edit this answer
    wrong_word = f"Добрый день, {hlink(m.from_user.full_name, f'tg://user?id={m.from_user.id}')}\n\n" \
                 f"⚠️ Если Ваше объявление удаляется в чате, то Вы можете разместить его " \
                 f"только на {hunderline('ПЛАТНОЙ ОСНОВЕ.')}\n" \
                 f"С тарифами на размещение можно ознакомиться в боте: @Vacansy_resume_bot\n\n" \
                 f"Администрация чата не несёт ответственности за размещаемую пользователями информацию и не исправляет её."

    text = m.text
    if m.caption:
        text = m.caption

    for w in context['stop_words']:
        # TODO replace to search in regexp
        if w.lower() in text.lower():
            # await scheduled_function(answer_mess, (m, wrong_word, None, 30))
            await db.jobs_add(message_id=2, chat_id=m.chat.id, text=wrong_word)
            try:
                await m.delete()
                logger.success(f'[delete] {m.chat.title} | {m.from_user.full_name}: {w[:10]}')
            except Exception as e:
                if "message can't be deleted" in e:
                    return
                adm = await check_bot_admin(m)
                if not adm:
                    await bot.send_message(user.client_id, no_admin_text)
                logger.error(f'[delete] {e} | {m.chat.title}({m.chat.id}): {w[:10]}')
            break

    for w in words_in_chat:
        if w.lower() in text.lower():
            # await scheduled_function(answer_mess, (m, wrong_word, None, 30))
            await db.jobs_add(message_id=2, chat_id=m.chat.id, text=wrong_word)
            try:
                await m.delete()
                logger.success(f'[delete] {m.chat.title} | {m.from_user.full_name}: {w[:10]}')
            except Exception as e:
                adm = await check_bot_admin(m)
                if not adm:
                    await bot.send_message(user.client_id, no_admin_text)
                logger.error(f'[delete] {e} | {m.chat.title}({m.chat.id}): {w[:10]}')
            break


@router.callback_query(
    MenuCategory.filter(F.category == 'require_channels'),
    MenuCategory.filter(F.action == 'check'),
    MenuCategory.filter(F.level == 10),
)
async def check_subscription_in_require_channels(call: CallbackQuery, callback_data: MenuCategory, context: dict,
                                                 state: FSMContext):
    users = context["users"]
    require_channel_id = []
    for c in users:
        if call.message.chat.id in c.chats_id:
            if call.message.chat.id in c.require_channel_id.keys():
                require_channel_id = c.require_channel_id[call.message.chat.id]
            break
    subscribe = await check_subs(require_channel_id, callback_data.chat_id)
    if subscribe:
        await call.answer(text='Умничка, теперь твои сообщения не будут удаляться. Пиши на здоровье', show_alert=True)
        await call.message.delete()
        return
    elif not subscribe:
        await call.answer(text='Ты не на всё подписался', show_alert=True)

# @router.callback_query()
# async def nobody_handler(call: types.CallbackQuery, context: dict):
#     logger.debug(call)
